---
order: 1.2
category: '@threlte/extras'
sourcePath: 'packages/extras/src/lib/components/HTML/HTML.svelte'
title: <HTML>
type: 'component'
componentSignature:
  {
    extends: { type: 'Group', url: 'https://threejs.org/docs/index.html#api/en/objects/Group' },
    exports:
      [
        {
          name: 'startRendering',
          type: '() => void',
          description: 'Manually start the render task'
        },
        { name: 'stopRendering', type: '() => void', description: 'Manually stop the render task' },
        {
          description: 'renders a single frame of the provided html',
          name: 'render',
          type: '() => void'
        }
      ],
    props:
      [
        { name: 'transform', type: 'boolean', default: 'false', required: false },
        { name: 'calculatePosition', type: '(
            obj: Object3D,
            camera: Camera,
            size: { width: number; height: number }
            ) => [number, number]', required: false },
        { name: 'eps', type: 'number', default: '0.001', required: false },
        {
          name: 'occlude',
          type: "boolean | THREE.Object3D[] | 'blending'",
          default: 'false',
          required: false
        },
        {
          name: 'zIndexRange',
          type: '[number, number]',
          default: '[16777271, 0]',
          required: false
        },
        { name: 'sprite', type: 'boolean', default: 'false', required: false },
        {
          name: 'pointerEvents',
          type: "'auto' | 'none' | 'visiblePainted' | 'visibleFill' | 'visibleStroke' | 'visible' | 'painted' | 'fill' | 'stroke' | 'all' | 'inherit'",
          default: "'auto'",
          required: false
        },
        { name: 'center', type: 'boolean', default: 'false', required: false },
        { name: 'fullscreen', type: 'boolean', default: 'false', required: false },
        { name: 'distanceFactor', type: 'number', default: 'undefined', required: false },
        { name: 'as', type: 'keyof HTMLElementTagNameMap', default: "'div'", required: false },
        { name: 'portal', type: 'HTMLElement', default: 'undefined', required: false },
        { name: 'castShadow', type: 'boolean', default: 'undefined', required: false },
        { name: 'receiveShadow', type: 'boolean', default: 'undefined', required: false },
        { name: 'material', type: 'THREE.Material', default: 'undefined', required: false },
        { name: 'geometry', type: 'THREE.BufferGeoemtry', default: 'undefined', required: false },
        {
          name: 'autoRender',
          type: 'boolean',
          default: 'true',
          required: false,
          description: 'whether the render task should be ran every frame'
        }
      ]
  }
---

This component is a port of [drei's `<Html>`
component](https://github.com/pmndrs/drei#html). It allows you to tie HTML
content to any object of your scene. It will be projected to the objects
whereabouts automatically.

<Tip type="warning">
	The container of your `<Canvas>` component needs to be set to `position:
	relative | absolute | sticky | fixed`. This is because the DOM element will
	be mounted as a sibling to the `<canvas>` element.
</Tip>

<Example path="extras/html/basic" />

## Basic example

```svelte
<script lang="ts">
  import { HTML } from '@threlte/extras'
</script>

<HTML>
  <h1>Hello, World!</h1>
</HTML>
```

### Transform

`transform` applies matrix3d transformations.

```svelte
<script lang="ts">
  import { HTML } from '@threlte/extras'
</script>

<HTML transform>
  <h1>Hello World</h1>
</HTML>
```

### Occlude

`<Html>` can be occluded behind geometry using the occlude `occlude` property.

```svelte
<script lang="ts">
  import { HTML } from '@threlte/extras'
</script>

<HTML
  transform
  occlude
>
  <h1>Hello World</h1>
</HTML>
```

Setting `occlude` to `"blending"` will allow objects to partially occlude the
`<HTML>` component.

<Tip type="warning">
	This occlusion mode requires the `<canvas>` element to have `pointer-events`
	set to `none`. Therefore, any events like those in `OrbitControls` must be
	set on the canvas parent. Extras components like `<OrbitControls>` do this
	automatically.
</Tip>

<Example path="extras/html/phone" />

### Visibility change event

Use the property `occlude` and bind to the event `visibilitychange` to
implement a custom hide/show behaviour.

```svelte
<script lang="ts">
  import { HTML } from '@threlte/extras'

  const onVisibilityChange = (isVisible: boolean) => {
    console.log(isVisible)
  }
</script>

<HTML
  transform
  occlude
  onvisibilitychange={onVisibilityChange}
>
  <h1>Hello World</h1>
</HTML>
```

<Tip type="info">
	When binding to the event `visibilitychange` the contents of `<HTML>` is
	_not_ automatically hidden when it's occluded.
</Tip>

### Sprite rendering

Use the property `sprite` in `transform` mode to render the contents of
`<HTML>` as a sprite.

```svelte
<script lang="ts">
  import { HTML } from '@threlte/extras'
</script>

<HTML
  transform
  sprite
>
  <h1>Hello World</h1>
</HTML>
```

### Center

Add a -50%/-50% css transform with `center` when _not_ in `transform` mode.

```svelte
<script lang="ts">
  import { HTML } from '@threlte/extras'
</script>

<HTML center>
  <h1>Hello World</h1>
</HTML>
```

### Portal

Use the property `portal` to mount the contents of the `<HTML>` component on
another `HTMLElement`. By default the contents are mounted as a sibling to the
rendering `<canvas>`.

```svelte
<script lang="ts">
  import { HTML } from '@threlte/extras'
</script>

<HTML portal={document.body}>
  <h1>Hello World</h1>
</HTML>
```

## Pausing the render task

`<HTML>` has an `autoRender` prop that you can use to pause its
render task. If at some point you no longer need to update `<HTML>`,
you can set `autoRender` to `false`. If you need to resume updates,
set `autoRender` back to `true`.

`<HTML>` also exports its internal render task and the `startRendering`,
`stopRendering`, and `render` functions so you can either manually render
or start and stop the internal task based on your needs.

```svelte title="manually-rendering.svelte"
<script lang="ts">
  import { HTML } from '@threlte/extras'

  let html = $state<HTML>()

  $effect(() => {
    html?.render()
  })
</script>

<HTML
  autoRender={false}
  bind:this={html}
>
  <h1>Hello World</h1>
</HTML>
```

```svelte title="toggle-rendering.svelte"
<script lang="ts">
  import { HTML } from '@threlte/extras'

  let html = $state<HTML>()

  // turn this on and off in accordance with your application
  let renderWhileTrue = $state(false)

  $effect(() => {
    if (renderWhileTrue) {
      html?.startRendering()
      // always stop rendering if it was started
      return () => {
        html?.stopRendering()
      }
    }
  })
</script>

<HTML
  autoRender={false}
  bind:this={html}
>
  <h1>Hello World</h1>
</HTML>
```

In both cases you should set `autoRender` to `false` so that the render task
doesn't automatically begin.

Lastly, you can access these functions from the `<HTML>`'s children snippet.

```svelte
<HTML autoRender={false}>
  {#snippet children({ render, startRendering, stopRendering })}
    <button onclick={startRendering}>start rendering</button>
    <button onclick={stopRendering}>stop rendering</button>
    <button onclick={render}>render a single frame</button>
  {/snippet}
</HTML>
```

## uikit

An alternative to using HTML for UI is
[uikit](https://pmndrs.github.io/uikit/docs/getting-started/vanilla). The
vanilla code has be wrapped into
[threlte-uikit](https://github.com/threlte/threlte-uikit) for use in
threlte projects. There are situations where this package is necessary, for
instance the `<HTML/>` component cannot be used within XR sessions.
